home *** CD-ROM | disk | FTP | other *** search
- ; DDIR.ASM -- Double Column Sorted DIR Command
-
- ; ========
-
- ; (C) Copyright Charles Petzold, 1985
-
- ;
-
- ; COM file format
-
- ;
-
-
-
- CSEG Segment
-
-
-
- Assume CS:CSEG, DS:CSEG
-
-
-
- Org 002Ch ; Offset of Environment
-
- Environment Label Byte
-
-
-
- Org 007Bh ; Parameter for COMMAND.COM
-
- NewParameter Label Byte
-
-
-
- Org 0080h ; Parameter passed to program
-
- OldParameter Label Byte
-
-
-
- Org 0100h ; Entry point
-
- Entry: Jmp Begin
-
-
-
- ; All Data
-
- ; --------
-
-
-
- db '(C) Copyright Charles Petzold, 1985'
-
-
-
- DosVersMsg db "Needs DOS 2.0 +$" ; Error messages
-
- MemAllocMsg db "Memory Problem$"
-
- CommandMsg db "COMMAND Problem$"
-
-
-
- Comspec db "COMSPEC=" ; Search string in environment
-
- CommandAsciiz dd ? ; Eventual pointer to COMMAND
-
-
-
- ParamBlock dw ? ; Parameter Block for EXEC
-
- dw NewParameter,? ; First ? must be replaced
-
- dw 5Ch,? ; with Environment segment;
-
- dw 6Ch,? ; others with this segment
-
-
-
- OldInterrupt21 dd ? ; For vector address storage
-
-
-
- BufferPtr dw Offset FileBuffer ; For storing files listing
-
- CharCounter dw 0 ; Keeps track of characters
-
- NowDoingFile db 0 ; Flagged for file printed
-
- WithinFileList db 0 ; Flagged for file list
-
- FileCounter dw 0 ; Keeps track of files
-
- LineCounter db 0 ; For pausing at screen end
-
-
-
- PauseMessage db 6 dup (205)," Press any key to continue "
-
- db 6 dup (205),181
-
- PauseMsgEnd Label Byte
-
-
-
- ; Check DOS Version
-
- ; -----------------
-
-
-
- Begin: Mov AH,30h ; DOS Version function call
-
- Int 21h ; Call DOS
-
- Cmp AL,2 ; Check if version 2
-
- Jae DosVersOK ; If equal or over, all OK
-
-
-
- Mov DX,Offset DosVersMsg ; Wrong DOS version message
-
- ErrorExit: Mov AH,9 ; Set up for string write
-
- Int 21h ; Call DOS for message
-
-
-
- Int 20h ; Dishonorable discharge
-
-
-
- ; Adjust stack and un-allocate rest of memory
-
- ; -------------------------------------------
-
-
-
- DosVersOK: Mov DI,Offset FileBuffer ; Place to save files
-
- Mov CX,528 * 39 ; Allow room for 528 files
-
- Mov AL,' ' ; Will clear with blanks
-
- Cld ; Forward direction
-
- Rep Stosb ; Clear the area
-
-
-
- Mov BX,(Offset FileBuffer) + (528 * 39) + 100h
-
- ; New end of program
-
- Mov SP,BX ; Set the stack pointer
-
- Add BX,15 ; Add 15 for rounding
-
- Mov CL,4 ; Number of shifts
-
- Shr BX,CL ; Convert AX to segment
-
-
-
- Mov AH,4Ah ; DOS call to shrink down
-
- Int 21h ; allocated memory
-
-
-
- Mov DX,Offset MemAllocMsg ; Possible error message
-
- Jc ErrorExit ; Only print it if Carry set
-
-
-
- ; Search for Comspec in Environment
-
- ; ---------------------------------
-
-
-
- Mov ES,[Environment] ; Environment Segment
-
- Sub DI,DI ; Start search at beginning
-
- Cld ; String increment to forward
-
-
-
- TryThis: Cmp Byte Ptr ES:[DI],0 ; See if end of environment
-
- Jz NoFindComSpec ; If so, we have failed
-
-
-
- Push DI ; Save environment pointer
-
- Mov SI,Offset ComSpec ; String to search for
-
- Mov CX,8 ; Characters in search string
-
- Repz Cmpsb ; Check if strings are same
-
- Pop DI ; Get back the pointer
-
-
-
- Jz FoundComspec ; Found string only zero flag
-
-
-
- Sub AL,AL ; Zero out AL
-
- Mov CX,8000h ; Set for big search
-
- Repnz Scasb ; Find the next zero in string
-
- Jmp TryThis ; And do the search from there
-
-
-
- NoFindComSpec: Mov DX,Offset CommandMsg ; Message for COMSPEC error
-
- Jmp ErrorExit ; Print it and exit
-
-
-
- FoundComspec: Add DI,8 ; So points after 'COMSPEC='
-
- Mov Word Ptr [CommandASCIIZ],DI ; Save the address of
-
- Mov Word Ptr [CommandASCIIZ + 2],ES ; COMMAND ASCIIZ
-
-
-
- ; Set up parameter block for EXEC call
-
- ; ------------------------------------
-
-
-
- Mov [ParamBlock],ES ; Segment of Environment string
-
- Mov [ParamBlock + 4],CS ; Segment of this program
-
- Mov [ParamBlock + 8],CS ; so points to FCB's
-
- Mov [ParamBlock + 12],CS ; and NewParameter
-
-
-
- ; Save and set Interrupt 21h vector address
-
- ; -----------------------------------------
-
-
-
- Mov AX,3521h ; DOS call to get Interrupt 21
-
- Int 21h ; vector address
-
- Mov Word Ptr [OldInterrupt21],BX ; Save offset
-
- Mov Word Ptr [OldInterrupt21 + 2],ES ; And segment
-
-
-
- Mov DX,Offset NewInterrupt21; Address of new Interrupt 21
-
- Mov AX,2521h ; Do DOS call to
-
- Int 21h ; set the new address
-
-
-
- ; Fix up new parameter for "/C DIR" String
-
- ; ------------------------------------
-
-
-
- Mov AL,[OldParameter] ; Number of parameter chars
-
- Add AL,5 ; We'll be adding five more
-
- Mov [NewParameter],AL ; Save it
-
- Mov Word Ptr [NewParameter + 1],'C/' ; i.e. "/C"
-
- Mov Word Ptr [NewParameter + 3],'ID' ; Then "DI"
-
- Mov Byte Ptr [NewParameter + 5],'R' ; And "R"
-
-
-
- ; Load COMMAND.COM
-
- ; -----------------
-
-
-
- Push CS ; Push this segment so we can
-
- Pop ES ; set ES to it
-
- Mov BX,Offset ParamBlock ; ES:BX = address of block
-
- Lds DX,[CommandAsciiz] ; DS:DX = address of ASCIIZ
-
- Mov AX,4B00h ; EXEC call 4Bh, type 0
-
- Int 21h ; Load command processor
-
-
-
- ; Return from COMMAND.COM
-
- ; -----------------------
-
-
-
- Mov AX,CS ; Get this segment in AX
-
- Mov DS,AX ; Set DS to it
-
- Mov SS,AX ; And SS for stack segment
-
- Mov SP,(Offset FileBuffer) + (528 * 39) + 100h
-
- ; Set Stack again
-
-
-
- PushF ; Save Carry for error check
-
- Push DS ; Save DS during next call
-
-
-
- Mov DX,Word Ptr [OldInterrupt21] ; Old Int 21 offset
-
- Mov DS,Word Ptr [OldInterrupt21 + 2]; and segment
-
- Mov AX,2521h ; Call DOS to set vector
-
- Int 21h ; address to original
-
-
-
- Pop DS ; Restore DS to this segment
-
- PopF ; Get back Carry flage
-
-
-
- Jnc NormalEnd ; Continue if no error
-
-
-
- Mov DX,Offset CommandMsg ; Otherwise we'll print error
-
- Jmp ErrorExit ; message and exit
-
-
-
- NormalEnd: Int 20h ; Terminate program
-
-
-
- ; New Interrupt 21h
-
- ; -----------------
-
-
-
- NewInterrupt21 Proc Far
-
-
-
- Sti ; Allow further interrupts
-
- Cmp AH,40h ; Check if file / device write
-
- Je CheckHandle ; If so, continue checks
-
-
-
- SkipIntercept: Jmp CS:[OldInterrupt21] ; Just jump to old interrupt
-
-
-
- CheckHandle: Cmp BX,1 ; Check if standard output
-
- Jne SkipIntercept ; Not interested if not
-
-
-
- PushF ; Push all registers that
-
- Push AX ; we'll be messing with
-
- Push CX
-
- Push SI
-
- Push DI
-
- Push ES
-
-
-
- Push CS ; Push the code segment
-
- Pop ES ; So we can set ES to it
-
- Cld ; Forward for string transfers
-
- Mov SI,DX ; Now DS:SI = text source
-
- Mov DI,CS:[BufferPtr] ; And ES:DI = text destination
-
-
-
- Cmp CX,2 ; See if two chars to write
-
- Jne RegularChars ; If not, can't be CR/LF
-
-
-
- Cmp Word Ptr DS:[SI],0A0Dh ; See if CR/LF being written
-
- Jne RegularChars ; Skip rest if not CR/LF
-
-
-
- Mov CX,CS:[CharCounter] ; Get characters in line
-
- Mov CS:[CharCounter],0 ; Start at new line
-
- Cmp CS:[NowDoingFile],1 ; See if CR/LF terminates file
-
- Jnz AllowTransfer ; If not, just write to screen
-
-
-
- Mov AX,39 ; Max characters per line
-
- Sub AX,CX ; Subtract those passed
-
- Add CS:[BufferPtr],AX ; Kick up pointer by that
-
- Mov CS:[NowDoingFile],0 ; Finished with file
-
- Jmp PopAndReturn ; So just return to COMMAND
-
-
-
- RegularChars: Add CS:[CharCounter],CX ; Kick up counter by number
-
- Cmp CS:[CharCounter],CX ; See if beginning of line
-
- Jne NotLineBegin ; If not, must be in middle
-
-
-
- Cmp Byte Ptr DS:[SI],' ' ; See if first char is blank
-
- Jne ItsAFile ; If not, it's a file line
-
-
-
- Cmp CS:[WithinFileList],1 ; See if doing file listing
-
- Jne AllowTransfer ; If not, just print stuff
-
-
-
- Call SortAndList ; Files done -- sort and list
-
- Mov CS:[WithinFileList],0 ; Not doing files now
-
- Jmp Short AllowTransfer ; So just print the stuff
-
-
-
- ItsAFile: Cmp CS:[FileCounter],528 ; See if 11 buffer filled up
-
- Jb NotTooManyFiles ; If not just continue
-
-
-
- Push CX ; Otherwise, save this register
-
- Call SortAndList ; Print all up to now
-
- Mov CS:[FileCounter],0 ; Reset the counter
-
- Mov DI,Offset FileBuffer ; And the pointer
-
- Mov CS:[BufferPtr],DI ; Save the pointer
-
- Mov CX,528 * 39 ; Will clear for 528 files
-
- Mov AL,' ' ; With a blank
-
- Rep Stosb ; Clear it out
-
- Pop CX ; And get back register
-
-
-
- NotTooManyFiles:Mov CS:[WithinFileList],1 ; We're doing files now
-
- Mov CS:[NowDoingFile],1 ; And a file in particular
-
- Inc CS:[FileCounter] ; So kick up this counter
-
-
-
- NotLineBegin: Cmp CS:[NowDoingFile],1 ; See if doing files
-
- Je StoreCharacters ; If so, store the stuff
-
-
-
- AllowTransfer: Pop ES ; Pop all the registers
-
- Pop DI
-
- Pop SI
-
- Pop CX
-
- Pop AX
-
- PopF
-
-
-
- Jmp SkipIntercept ; And go to DOS for print
-
-
-
- StoreCharacters:Mov DI,CS:[BufferPtr] ; Set destination
-
- Rep Movsb ; Move characters to buffer
-
- Mov CS:[BufferPtr],DI ; And save new pointer
-
-
-
- PopAndReturn: Pop ES ; Pop all the registers
-
- Pop DI
-
- Pop SI
-
- Pop CX
-
- Pop AX
-
- PopF
-
-
-
- Mov AX,CX ; Set for COMMAND.COM
-
- Clc ; No error here
-
- Ret 2 ; Return with CY flag cleared
-
-
-
- NewInterrupt21 EndP
-
-
-
- ; Sort Files
-
- ; ----------
-
-
-
- SortAndList: Push BX ; Push a bunch of registers
-
- Push DX
-
- Push SI
-
- Push DS
-
-
-
- Push CS ; Push CS
-
- Pop DS ; so we can set DS to it
-
- Assume DS:CSEG ; And inform the assembler
-
-
-
- Mov DI,Offset FileBuffer ; This is the beginning
-
- Mov CX,[FileCounter] ; Number of files to sort
-
- Dec CX ; Loop needs one less than that
-
- Jcxz AllSorted ; But zero means only one file
-
-
-
- SortLoop1: Push CX ; Save the file counter
-
- Mov SI,DI ; Set source to destination
-
-
-
- SortLoop2: Add SI,39 ; Set source to next file
-
-
-
- Push CX ; Save the counter,
-
- Push SI ; compare source,
-
- Push DI ; and compare destination
-
-
-
- Mov CX,39 ; 39 characters to compare
-
- Repz Cmpsb ; Do the compare
-
- Jae NoSwitch ; Jump if already in order
-
-
-
- Pop DI ; Get back these registers
-
- Pop SI
-
-
-
- Push SI ; And push them again for move
-
- Push DI
-
-
-
- Mov CX,39 ; 39 characters
-
- SwitchLoop: Mov AL,ES:[DI] ; Character from destination
-
- Movsb ; Source to destination
-
- Mov DS:[SI - 1],AL ; Character to source
-
- Loop SwitchLoop ; For the rest of the line
-
-
-
- NoSwitch: Pop DI ; Get back the registers
-
- Pop SI
-
- Pop CX
-
- Loop SortLoop2 ; And loop for next file
-
-
-
- Pop CX ; Get back file counter
-
- Add DI,39 ; Compare with next file
-
- Loop SortLoop1 ; And loop again
-
-
-
- ; Now Display Sorted Files
-
- ; ------------------------
-
-
-
- AllSorted: Mov SI,Offset FileBuffer ; This is the beginning
-
- Mov CX,[FileCounter] ; Number of files to list
-
- Inc CX ; In case CX is odd
-
- Shr CX,1 ; CX now is number of lines
-
-
-
- SetIncrement: Mov BX,24 * 39 ; Increment for double list
-
- Cmp CX,24 ; But use it only if a full
-
- Jae LineLoop ; screen is printed
-
-
-
- Mov AX,39 ; Otherwise find increment
-
- Mul CX ; by multiplying CX by 39
-
- Mov BX,AX ; And make that the increment
-
-
-
- LineLoop: Call PrintFile ; Print the first column file
-
- Mov AL,' ' ; Skip one space
-
- Call PrintChar ; by printing blank
-
- Mov AL,179 ; Put a line down the middle
-
- Call PrintChar
-
- Mov AL,' ' ; Skip another space
-
- Call PrintChar
-
-
-
- Add SI,BX ; Bump up source by increment
-
- Sub SI,39 ; But kick down by 39
-
-
-
- Call PrintFile ; Print the second column file
-
- Call CRLF ; And terminate line
-
-
-
- Sub SI,BX ; Bring pointer back down
-
-
-
- Inc [LineCounter] ; One more line completed
-
- Cmp [LineCounter],24 ; Have we done whole screen?
-
- Jz PauseAtEnd ; If so, gotta pause now
-
-
-
- Loop LineLoop ; Otherwise just loop
-
- Jmp Short AllFinished ; And jump out when done
-
-
-
- PauseAtEnd: Mov [LineCounter],0 ; Reset the counter
-
- Add SI,BX ; Go to next file
-
-
-
- Push BX ; Save these registers
-
- Push CX
-
- Mov DX,Offset PauseMessage ; Test to print
-
- Mov CX,Offset PauseMsgEnd - Offset PauseMessage
-
- ; Number of characters
-
- Mov BX,2 ; Standard ERROR Output
-
- Mov AH,40h ; Display to screen
-
- Int 21h ; By calling DOS
-
- Pop CX ; Retrieve pushed registers
-
- Pop BX
-
-
-
- Mov AH,8 ; Wait for character
-
- Int 21h ; Through DOS call
-
-
-
- Call CRLF ; Go to next line
-
-
-
- Loop SetIncrement ; And recalculate increment
-
-
-
- AllFinished: Pop DS ; Done with subroutine
-
- Pop SI
-
- Pop DX
-
- Pop BX
-
- Ret ; So return to caller
-
-
-
- ; Display Routines
-
- ; ----------------
-
-
-
- PrintChar: Mov DL,AL ; Print character in AL
-
- Mov AH,2 ; By simple DOS call
-
- Int 21h
-
- Ret ; And return
-
-
-
- CRLF: Mov AL,13 ; Print a carriage return
-
- Call PrintChar
-
- Mov AL,10 ; And a line feed
-
- Call PrintChar
-
- Ret ; And return
-
-
-
- PrintString: Lodsb ; Get character from SI
-
- Call PrintChar ; Print it
-
- Loop PrintString ; Do that CX times
-
- Ret ; And return
-
-
-
- PrintFile: Push CX ; Save the counter
-
- Mov CX,32 ; Bytes for Name, Size, & Date
-
- Call PrintString ; Print it
-
- Inc SI ; Skip one space before time
-
- Mov CX,6 ; Bytes for Time
-
- Call PrintString ; It's a print!
-
- Pop CX
-
- Ret ; And return
-
-
-
- FileBuffer Label Byte ; Points to end of code
-
-
-
- CSEG EndS ; End of segment
-
-
-
- End Entry ; Denotes entry point
-